<template>
  <div class="chat-container">
    <div class="messages" ref="messagesContainer">
      <div
        v-for="(msg, index) in messages"
        :key="index"
        :class="['message', msg.role]"
      >
        <!-- 头像 -->
        <div class="avatar" :class="msg.role">
          <img :src="msg.role === 'user' ? userAvatar : assistantAvatar" alt="avatar" />
        </div>
        <!-- 消息内容 -->
        <div class="content" v-html="renderMarkdown(msg.content)"></div>
      </div>
    </div>
    <div class="input-area">
      <div class="input-wrapper">
        <textarea
          v-model="inputText"
          @input="adjustHeight"
          @keyup.enter="handleEnter"
          placeholder="输入消息..."
          :maxlength="maxInputLength"
          ref="inputField"
        ></textarea>
        <button
          class="clear-btn"
          v-if="inputText"
          @click="clearInput"
          title="清空输入"
        >
          ×
        </button>
      </div>
      <div class="action-buttons">
        <span class="char-count">{{ inputText.length }}/{{ maxInputLength }}</span>
        <button
          @click="sendMessage"
          :disabled="isLoading || !inputText.trim()"
          class="send-btn"
        >
          <span v-if="!isLoading">发送</span>
          <svg v-else class="loading-spinner" viewBox="25 25 50 50">
            <circle cx="50" cy="50" r="20" fill="none" stroke-width="5"></circle>
          </svg>
        </button>
      </div>
    </div>
  </div>
</template>
<script setup>
import { ref, nextTick, onMounted } from 'vue';
import { marked } from 'marked';
import DOMPurify from 'dompurify';
// API 配置
const API_URL = 'http://localhost:11434/api/chat';
const API_KEY = import.meta.env.VITE_DASHSCOPE_API_KEY;
const maxInputLength = 10000;

// 响应式变量
const inputField = ref(null);
const messages = ref([]);
const inputText = ref('');
const isLoading = ref(false);
const messagesContainer = ref(null);
const renderMarkdown = (content) => {
   const rawHtml = marked.parse(content); // 将 Markdown 转换为 HTML
      const sanitizedHtml = DOMPurify.sanitize(rawHtml); // 清理 HTML
      return sanitizedHtml;
};
/**
 * 发送消息并处理流式响应
 */
 const sendMessage = async () => {
  if (!inputText.value.trim() || isLoading.value) return;

  const userMessage = inputText.value;
  messages.value.push({ role: 'user', content: userMessage });
  inputText.value = '';
  scrollToBottom();
  isLoading.value = true;

  try {
    const response = await fetch(API_URL, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        // Ollama 默认无需授权头
      },
      body: JSON.stringify({
        model: 'gemma2:2b', // 确保模型名称正确
        messages: messages.value, // 直接传递全部历史消息
        stream: true
      })
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const reader = response.body.getReader();
    const decoder = new TextDecoder();
    let assistantMessage = { role: 'assistant', content: '' };

    while (true) {
      const { done, value } = await reader.read();
      if (done) break;

      const chunk = decoder.decode(value);
      const lines = chunk.split('\n').filter(line => line.trim() !== '');

      for (const line of lines) {
        try {
          const parsed = JSON.parse(line);
          if (parsed.message) {
            assistantMessage.content += parsed.message.content;
          } else if (parsed.content) {
            assistantMessage.content += parsed.content;
          }

          // 更新最后一条消息或新增
          if (messages.value[messages.value.length - 1]?.role === 'assistant') {
            messages.value[messages.value.length - 1].content = assistantMessage.content;
          } else {
            messages.value.push({ ...assistantMessage });
          }

          scrollToBottom();
        } catch (e) {
          console.error('解析JSON失败:', e, '原始数据:', line);
        }
      }
    }
  } catch (error) {
    console.error('请求失败:', error);
    messages.value.push({
      role: 'system',
      content: `请求出错: ${error.message}`
    });
  } finally {
    isLoading.value = false;
    scrollToBottom();
  }
};
/**
 * 滚动至消息底部
 */
const scrollToBottom = () => {
  nextTick(() => {
    if (messagesContainer.value) {
      messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight;
    }
  });
};

/**
 * 根据内容调整输入框高度
 */
const adjustHeight = () => {
  if (inputField.value) {
    inputField.value.style.height = 'auto';
    inputField.value.style.height = `${inputField.value.scrollHeight}px`;
  }
};

/**
 * 处理回车事件（非 Shift + Enter 时发送消息）
 */
const handleEnter = (e) => {
  if (!e.shiftKey) {
    e.preventDefault();
    sendMessage();
  }
};

/**
 * 清空输入框
 */
const clearInput = () => {
  inputText.value = '';
  adjustHeight();
};

onMounted(() => {
  adjustHeight();
});
</script>

<style scoped>
.chat-container {
  width: 100%;
  margin: 0 auto;
  height: 100vh;
  display: flex;
  flex-direction: column;
  background: linear-gradient(to bottom, #f9f9f9, #ffffff);
}

.messages {
  flex: 1;
  padding: 20px;
  overflow-y: auto;
  border-bottom: 1px solid #ddd;
  scrollbar-width: thin;
  scrollbar-color: #bbb #f0f0f0;
}

.message {
  display: flex;
  align-items: flex-start;
  margin: 12px 0;
}

.message.user {
  justify-content: flex-end;
}

.message.assistant {
  justify-content: flex-start;
}

.avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  overflow: hidden;
  margin: 0 12px;
}

.avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.content {
  max-width: 75%;
  padding: 12px 16px;
  border-radius: 12px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  line-height: 1.6;
  word-break: break-word;
}

.message.user .content {
  background: #007bff;
  color: white;
  margin-left: auto;
  text-align: right;
}

.message.assistant .content {
  background: #ffffff;
  color: #333;
  margin-right: auto;
}

.input-area {
  padding: 15px;
  background: #ffffff;
  border-top: 1px solid #ddd;
}

.input-wrapper {
  position: relative;
  margin-bottom: 12px;
}

textarea {
  width: 100%;
  min-height: 50px;
  max-height: 200px;
  padding: 12px 40px 12px 15px;
  border: 1px solid #ccc;
  border-radius: 8px;
  resize: none;
  transition: border 0.3s ease;
}

textarea:focus {
  border-color: #007bff;
  box-shadow: 0 0 8px rgba(0, 123, 255, 0.3);
  outline: none;
}

.clear-btn {
  position: absolute;
  right: 10px;
  top: 50%;
  transform: translateY(-50%);
  background: none;
  border: none;
  color: #999;
  font-size: 18px;
  cursor: pointer;
}

.action-buttons {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.char-count {
  font-size: 12px;
  color: #666;
}

.send-btn {
  padding: 10px 24px;
  background: #007bff;
  color: white;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  display: flex;
  align-items: center;
  transition: background 0.3s ease;
}

.send-btn:hover {
  background: #0056b3;
}

.send-btn:disabled {
  background: #ccc;
  cursor: not-allowed;
}

.loading-spinner {
  width: 24px;
  height: 24px;
  animation: rotate 1s linear infinite;
}

.loading-spinner circle {
  stroke: #fff;
  stroke-linecap: round;
  animation: dash 1.5s ease-in-out infinite;
}

@keyframes rotate {
  100% {
    transform: rotate(360deg);
  }
}

@keyframes dash {
  0% {
    stroke-dasharray: 1, 150;
    stroke-dashoffset: 0;
  }
  50% {
    stroke-dasharray: 90, 150;
    stroke-dashoffset: -40;
  }
  100% {
    stroke-dasharray: 90, 150;
    stroke-dashoffset: -120;
  }
}
</style>
